package v.show.health.server.configure;

import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.hazelcast.config.*;
import com.hazelcast.spi.merge.PutIfAbsentMergePolicy;
import de.codecentric.boot.admin.server.config.AdminServerHazelcastAutoConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.List;

/**
 * 集群部署时同步消息
 *
 * @author whz
 */
@Slf4j
@Configuration
public class HazelcastConfigure {

    public static final String DEFAULT_NAME_EVENT_STORE_MAP = AdminServerHazelcastAutoConfiguration.DEFAULT_NAME_EVENT_STORE_MAP;
    public static final String DEFAULT_NAME_SENT_NOTIFICATIONS_MAP = AdminServerHazelcastAutoConfiguration.DEFAULT_NAME_SENT_NOTIFICATIONS_MAP;

    @Value("${health.hazelcast.backup.count:3}")
    private int backUpCount;

    @Value("${health.hazelcast.max.count:500}")
    private int maxCount;

    @Value("${health.hazelcast.batch.count:200}")
    private int batchCount;

    @Value("${health.hazelcast.cluster.enable:true}")
    private boolean enableCluster;

    @Value("${spring.application.name:health-checker}")
    private String appName;

    @Resource
    private DiscoveryClient client;


    @Bean
    public Config hazelcastConfig() {
        // event store
        MapConfig eventStoreMap = createMap(maxCount, batchCount, DEFAULT_NAME_EVENT_STORE_MAP);
        // notification store
        MapConfig sentNotificationsMap = createMap(maxCount, batchCount, DEFAULT_NAME_SENT_NOTIFICATIONS_MAP);

        Config config = new Config();
        config.addMapConfig(eventStoreMap);
        config.addMapConfig(sentNotificationsMap);
        config.setProperty("hazelcast.jmx", "true");

        List<String> ips = obtainClusterIps();
        log.info("health-check cluster ips;{}", ips);

        config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(enableCluster && ips.size() > 1);
        TcpIpConfig tcpIpConfig = config.getNetworkConfig().getJoin().getTcpIpConfig();
        tcpIpConfig.setEnabled(true);
        tcpIpConfig.setMembers(ips);
        return config;
    }

    private MapConfig createMap(int maxCount, int batchSize, String name) {
        return new MapConfig(name)
                .setInMemoryFormat(InMemoryFormat.OBJECT)
                .setBackupCount(backUpCount)
                .setEvictionConfig(new EvictionConfig()
                        .setMaxSizePolicy(MaxSizePolicy.USED_HEAP_PERCENTAGE)
                        .setEvictionPolicy(EvictionPolicy.LFU)
                        .setSize(maxCount))
                .setMaxIdleSeconds(30)
                .setMergePolicyConfig(new MergePolicyConfig(PutIfAbsentMergePolicy.class.getName(), batchSize))
                .setDataPersistenceConfig(new DataPersistenceConfig().setEnabled(true).setFsync(false));
    }


    private List<String> obtainClusterIps() {
        if (client == null) {
            log.warn("health check has not get discovery client.");
            return Lists.newArrayList("127.0.0.1");
        }
        List<String> ips = Lists.newArrayList();
        client.getInstances(appName).forEach(instance -> ips.add(instance.getHost()));
        return ips;
    }
}